<?php
defined('PATH_PK') or die();

use PKFrame\DataHandler\MatchHelper;
use PKFrame\Lib\BlackListIP;
use PKFrame\Lib\Cache;
use PKFrame\Lib\Files;
use PKFrame\Lib\Log;
use PKFrame\Lib\Out;
use PKFrame\Lib\Request;


if (!function_exists('path_app')) {
    function path_app($app): string
    {
        static $list_app;
        is_array($list_app) ?: $list_app = [];
        if (in_array($app, $list_app)) {
            return $list_app[$app];
        } else {
            $app = ucfirst($app);
            $path_app = PATH_APP . $app . DS;
            if (file_exists($path_app)) {
                $list_app[$app] = $path_app;
            } else {
                $path_app = PATH_ExtAPP . $app . DS;
                if (!file_exists($path_app)) {
                    die('Application not found, application name:' . $path_app);
                } else {
                    $list_app[$app] = $path_app;
                }
            }
            return $path_app;
        }
    }
}

if (!function_exists('toBool')) {
    function toBool(string $field, array $list_params, $return_null = false): int
    {
        if (array_key_exists($field, $list_params)) {
            $boolval = is_string($list_params[$field])
                ? filter_var($list_params[$field], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)
                : (bool)$list_params[$field];
            return ($boolval === null && !$return_null ? false : $boolval);
        } else {
            return false;
        }
    }
}

if (!function_exists('executeTime')) {
    /**
     * 计算程序执行时间
     * @param $start_time - 开始时间
     * @return int 单位ms
     */
    function executeTime($start_time): int
    {
        return round(microtime(true) - $start_time, 5);
    }
}

if (!function_exists('language')) {
    /**
     * 语言文件处理
     * @param $code
     * @param string $app (取决于应用区域，如：system)
     * @return mixed|string
     */
    function language($code, $app = null)
    {
        static $languageList = [];
        $app = !is_null($app) ? ucfirst($app) : \request()->module();
        // $languageType (语言的类型，如： zh-cn、en)
        $languageType = !empty(\request()->language()) && in_array(\request()->language(), ['en']) ? \request()->language() : 'zh-cn';
        // 应用语言包
        if (!empty($app) &&
            array_key_exists($app, $languageList) && array_key_exists($code, $languageList[$app])
            && array_key_exists($languageType, $languageList[$app][$code])
        ) {
            return $languageList[$app][$code][$languageType];
        } elseif (!array_key_exists($app, $languageList)) {
            $data = loader(path_app($app) . 'Data' . DS . 'Language', true);
            if (is_array($data)) {
                $languageList[$app] = $data;
                if (array_key_exists($code, $data) && array_key_exists($languageType, $data[$code])) {
                    return $data[$code][$languageType];
                }
            }
        }
        // 底层共用语言包
        if (
            array_key_exists('Common', $languageList) && array_key_exists($code, $languageList['Common'])
            && array_key_exists($languageType, $languageList['Common'][$code])
        ) {
            return $languageList['Common'][$code][$languageType];
        } elseif (!array_key_exists('Common', $languageList)) {
            $dir = PATH_Frame . 'Language';
            $data = loader($dir, true);
            if (is_array($data)) {
                $languageList['Common'] = $data;
                if (array_key_exists($code, $data) && array_key_exists($languageType, $data[$code])) {
                    return $data[$code][$languageType];
                }
            }
        }
        return $code;
    }
}

if (!function_exists('loader')) {

    /**
     * 判断是否已经加载
     * @param $file_path - 加载文件的路径
     * @param bool $isReturnData
     * @return bool|mixed|string
     */
    function loader($file_path, bool $isReturnData = false)
    {
        $fileExt = '.php';
        static $loadExistsList = [];
        is_file($file_path) ?: $file_path .= $fileExt;
        $file_md5 = md5($file_path);
        if ($isReturnData && file_exists($file_path)) {
            /** @noinspection PhpIncludeInspection */
            return strpos($file_path, $fileExt) ? include("$file_path") : fileHelper()->GetContentsByDisk($file_path);
        }
        if (array_key_exists($file_md5, $loadExistsList)) {
            return true;
        } elseif (pathinfo($file_path) && file_exists($file_path)) {
            $loadExistsList[$file_md5] = $file_path;
            //        print_r($loadExistsList);
            /** @noinspection PhpIncludeInspection */
            include_once("$file_path");
            return true;
        }
        return false;
    }
}

if (!function_exists('dict')) {
    /**
     * 查询字典
     * @param $key
     * @param string|null $app
     * @return mixed
     */
    function dict($key, string $app = null)
    {
        static $_dictList;
        $app = is_null($app) ? request()->module() : ucfirst($app);
        if (is_array($_dictList) && array_key_exists($key, $_dictList)) {
            return $_dictList[$key];
        } else {
            $_dictList = [];
        }
        $_dictList_app = loader(path_app($app) . 'Data' . DS . 'Dictionaries', true);
        !is_array($_dictList_app) ?: $_dictList = array_merge($_dictList, $_dictList_app);
        if (array_key_exists($key, $_dictList)) {
            return $_dictList[$key];
        }
        $_dictList_base = loader(PATH_PK . 'Dictionaries', true);
        !is_array($_dictList_base) ?: $_dictList = array_merge($_dictList, $_dictList_base);
        if (array_key_exists($key, $_dictList)) {
            return $_dictList[$key];
        }
        return '';
    }
}

if (!function_exists('isInstall')) {
    /**
     * 是否需要安装
     * @return bool
     */
    function isInstall(): bool
    {
        if (file_exists(PATH_CACHE)) {
            $service_fingerprint = \cache()->Disk()->Read(SYSTEM_LOCK);
            $config_db = \cache()->Disk()->ReadByConfig('DataBase');
            if (empty($service_fingerprint) || empty($config_db)) {
                return true;
            }
            return \request()->ServerFingerprint() != $service_fingerprint;
        } else {
            return true;
        }
    }
}

if (!function_exists('cache')) {
    /**
     * 缓存的处理
     * @return Cache
     */
    function cache(): Cache
    {
        return Cache::getInstance();
    }
}

if (!function_exists('fileHelper')) {
    /**
     * 文件管理器
     * @return Files
     */
    function fileHelper(): Files
    {
        return Files::getInstance();
    }
}

if (!function_exists('logger')) {
    /**
     * 日志
     * @param string|null $log_dir 保存路径
     * @return Log
     */
    function logger(string $log_dir = null): Log
    {
        static $cls_log;
        $log_dir = is_null($log_dir) ? 'Log' : ucfirst($log_dir);;
        if (is_array($cls_log) && array_key_exists($log_dir, $cls_log)) {
            return $cls_log[$log_dir];
        }
        is_array($cls_log) ?: $cls_log = [];
        $cls_log[$log_dir] = Log::instance($log_dir);
        return $cls_log[$log_dir];
    }
}

if (!function_exists('out')) {
    /**
     * 输出
     * @return Out
     */
    function out(): Out
    {
        return Out::getInstance();
    }
}

if (!function_exists('http_response_code')) {
    /**
     * 获取/设置响应的 HTTP 状态码
     * 该函数开始支持 php vers 5.4.0
     * @param $code
     */
    function http_response_code($code)
    {
        \out()->HttpResponseCode($code);
    }
}

if (!function_exists('getLocationByIp')) {

    /**
     * 根据ip定位
     * @param $ip
     * @param $type
     * @return string | array
     * @throws Exception
     */
    function getLocationByIp($ip, $type = 1)
    {
        $ip2region = new Ip2Region();
        $info = $ip2region->btreeSearch($ip);
        $city_id = $info['city_id'];
        $info = explode('|', $info['region']);
        $address = '';
        foreach ($info as $vo) {
            if ('0' !== $vo) {
                $address .= $vo . '-';
            }
        }
        switch ($type) {
            case 'cityId':
                return $city_id;
                break;
            case 'city':
                return array('cityId' => $city_id, 'city' => rtrim($address, '-'));
                break;
            case 'area':
                return array('area' => rtrim($address, '-'), 'city' => $info['3']);
                break;
            default:
                return rtrim($address, '-');
                break;
        }
    }
}

if (!function_exists('request')) {
    /**
     * 获取当前Request对象实例
     * @return Request
     */
    function request(): Request
    {
        return Request::instance();
    }
}

if (!function_exists('str_cut')) {
    /**
     * 字符串的截取长度
     * @param string|null $str
     * @param int $cut_length
     * @param int $if_length
     * @return string
     */
    function str_cut(string $str = null, int $cut_length = 100, int $if_length = 0): string
    {
        $if_length > 0 ?: $if_length = $cut_length;
        if (strlen($str) > $if_length) {
            if (function_exists('mb_strcut')) {
                return mb_strcut($str, 0, $cut_length, 'utf8') . '…';
            } elseif (function_exists('mb_substr')) {
                return mb_substr($str, 0, $cut_length, 'utf8') . '…';
            } else {
                return str_cut($str, $cut_length);
            }
        } else {
            return is_string($str) ? $str : '';
        }
    }
}

/**
 * 自定义错误处理
 * @param $errNo
 * @param $errStr
 * @param $errFile
 * @param $errLine
 */
function handlerError($errNo, $errStr, $errFile, $errLine)
{
    switch ($errNo) {
        case E_ERROR:
        case E_PARSE:
        case E_CORE_ERROR:
        case E_COMPILE_ERROR:
        case E_USER_ERROR:
        case E_STRICT:
            ob_end_clean();
            \logger()->ERROR($errStr, $errNo, $errFile, $errLine);
            \out()->notice($errStr);
            break;
        case E_USER_WARNING:
        case E_USER_NOTICE:
            \logger()->WARNING($errStr, $errNo, $errFile, $errLine);
            break;
        default:
            //            Log::ERROR($errStr, $errNo, $errFile, $errLine);
            break;
    }
}

if (!function_exists('handleShutdown')) {
    /**
     * 致命错误捕获
     */
    function handleShutdown()
    {
        // 如果是因为严重错误(未被捕获)导致脚本退出, 则需要处理(作为对 set_error_handler的补充)
        // 以下错误无法被 set_error_handler 捕获: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING
        if (
            !is_null($error = error_get_last()) &&
            in_array($error['type'], array(E_COMPILE_ERROR, E_CORE_ERROR, E_ERROR, E_PARSE))
        ) {
            // handleException() 函数同时处理 set_exception_handler
            handlerException(new \ErrorException(
                $error['message'],
                $error['type'],
                0,
                $error['file'],
                $error['line']
            ));
        }
    }
}

if (!function_exists('handlerException')) {
    function handlerException(\Exception $ex)
    {
        \logger()->WARNING($ex->getMessage(), $ex->getCode(), $ex->getFile(), $ex->getLine());
        \out()->notice($ex->getMessage());
    }
}

if (!function_exists('handlerThrowable')) {
    function handlerThrowable(\Throwable $ex)
    {
        \logger()->WARNING($ex->getMessage(), $ex->getCode(), $ex->getFile(), $ex->getLine());
        \out()->notice($ex->getMessage());
    }
}

if (!function_exists('blackListIP')) {
    function blackListIP(): BlackListIP
    {
        return BlackListIP::getInstance();
    }
}

if (!function_exists('run')) {
    function run()
    {
        $guest_ip = \request()->GuestIP();
        \blackListIP()->IsExists($guest_ip);
        \logger()->LOGS(
            $guest_ip,
            [
                'request_url' => \request()->url(),
                'request_referer' => \request()->referer(),
                'method' => \request()->method(),
                'post' => \request()->post()
            ]
        );
        \request()->route();
        $module_name = \request()->module();
        !empty($module_name) ?: $module_name = \request()->module(DEFAULT_MODULE);
        $ctrl_name = \request()->controller();
        !empty($ctrl_name) ?: $ctrl_name = \request()->controller(DEFAULT_CONTROLLER);
        $class_name = '\PKApp\\' . $module_name . '\\' . $ctrl_name;
        if (!class_exists($class_name)) {
            $class_name = '\PKExtApp\\' . $module_name . '\\' . $ctrl_name;
            class_exists($class_name) ?: out()->notice('not ' . $ctrl_name . ' controller');
        }
        $ctrl = new $class_name();
        $action = \request()->action();
        if (is_callable(array($ctrl, $action)) == false) {
            $action = 'Main';
            is_callable(array($ctrl, $action)) ?: out()->notice('controller no action ' . $action);
        }
        $ctrl->$action();
    }
}

register_shutdown_function('handleShutdown');
set_error_handler('handlerError');
set_exception_handler('handlerThrowable');
